ELB+EC2+RDS(Multi-AZ)構成をあえてActive-Standbyにする
はじめに
WebサーバとRDSでシステムを構成する際、冗長性を考慮し、以下のような構成にすることが多いかと思います。
- WebサーバをEC2複数台で構築し、複数AZに分散配置。ELBでロードバランシングする。
- RDSをMulti-AZで構築し、複数AZに分散配置。
これでAvailability Zoneレベルでの冗長性が確保されますので、例えばAvailability Zoneがメンテナンスや災害などで丸ごと停止した場合にもサービスを継続することが出来ます。
しかし、Availability Zoneレベルでの冗長性を確保したいが、Acitve-Activeな構成にはしたくない場合があります。例えば、Multi-AZ構成のRDSではプライマリDBインスタンスは常にどちらかのAZに存在しますが、AZを跨いだ通信はAZ内での通信よりレイテンシが大きくなります。DBとの通信がシビアなシステムでは、常にプライマリDBインスタンスと同じAvailability ZoneにいるEC2をActiveにしておきたい場合もあるでしょう。
そこで、ELBのヘルスチェックとAWS CLIを使って、ELB+EC2+RDS(Multi-AZ)構成をあえてActive-Standbyにするスクリプトを作ってみました。
ELBの設定
ELBでは以下のように、ヘルスチェックで確認するファイルを「ok.html」として指定しています。
スクリプト
EC2上で動かしているスクリプトは以下の内容になります。これをcronで定期的に動作させることで、
- プライマリDBインスタンスと同じAvailability ZoneにいるEC2でok.htmlが作成される
- プライマリDBインスタンスと違うAvailability ZoneにいるEC2でok.htmlが削除される。但し全てのEC2がOutOfServiceにならないよう、対向のEC2でok.htmlがアクセス可能になっていることを確認してから実施する。
- ELBから見て常に片方1台がinServiceとなる。
という動作になります。自EC2と対向EC2の区別は「Name」というtagによって判断しています。
#!/bin/bash # 対向EC2のIPアドレスを取得 PARTNER_IPADDR=`aws ec2 describe-instances --filter Name=tag-key,Values=Name Name=tag-value,Values="web02" | grep "PRIVATEIPADDRESSES" | awk '{print $4}'` # 自EC2のAvailability Zoneを取得 EC2AZ=`aws ec2 describe-instances --filter Name=tag-key,Values=Name Name=tag-value,Values="web01" | grep "PLACEMENT" | awk '{print $2}'` # RDSの現在のAvailability Zoneを取得 DBAZ=`aws rds describe-db-instances | grep "DBINSTANCES" | awk '{print $4}'` # 自EC2とRDSの現在のAvailability Zoneが一致する場合、ok.htmlを作成 if test $EC2AZ = $DBAZ ; then echo "match" echo "ok" > /var/www/html/ok.html # 自EC2とRDSのAvailability Zoneが一致しない場合 else echo "unmatch" # 対向EC2がアップしていることを確認し、自EC2のok.htmlを削除 STATUS=`curl -s http://$PARTNER_IPADDR/ok.html` if test $STATUS = "ok" ; then rm /var/www/html/ok.html # 自EC2とRDSのAvailability Zoneが一致しない場合でも # 対向のEC2がokで無ければ、ok.htmlを作成 else echo "ok" > /var/www/html/ok.html fi fi
まとめ
AZを跨ぐことによるネットワークのレイテンシにシビアなシステムに対する対処としてはSQLやRDSパラメータのチューニングが最適解ですが、システムの変更が困難な場合、このような対策も有効かと思います。